package com.gombe.credit.app.request;

import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class OkHttpUtil {
    private static volatile OkHttpUtil instance;
    private final OkHttpClient okHttpClient;

    private OkHttpUtil() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS);

        okHttpClient = builder.build();
    }

    public static OkHttpUtil getInstance() {
        if (instance == null) {
            synchronized (OkHttpUtil.class) {
                if (instance == null) {
                    instance = new OkHttpUtil();
                }
            }
        }
        return instance;
    }

    /**
     * GET 请求
     * @param url 请求地址
     * @param params 请求参数
     * @param headers 请求头
     * @param callback 回调接口
     */
    public void get(String url, Map<String, String> params, Map<String, String> headers, HttpCallback callback) {
        Request.Builder requestBuilder = new Request.Builder();
        // 添加请求头
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        // 构建带参数的URL
        String finalUrl = buildUrlWithParams(url, params);
        requestBuilder.url(finalUrl).get();
        Request request = requestBuilder.build();
        executeRequest(request, callback);
    }

    /**
     * POST 表单请求
     * @param url 请求地址
     * @param params 表单参数
     * @param headers 请求头
     * @param callback 回调接口
     */
    public void postForm(String url, Map<String, String> params, Map<String, String> headers, HttpCallback callback) {
        FormBody.Builder formBuilder = new FormBody.Builder();
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                formBuilder.add(entry.getKey(), entry.getValue());
            }
        }
        FormBody formBody = formBuilder.build();
        post(url, formBody, headers, callback);
    }

    /**
     * POST JSON 请求
     * @param url 请求地址
     * @param json JSON字符串
     * @param headers 请求头
     * @param callback 回调接口
     */
    public void postJson(String url, String json, Map<String, String> headers, HttpCallback callback) {
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody requestBody = RequestBody.create(json, mediaType);
        post(url, requestBody, headers, callback);
    }

    /**
     * 文件上传
     * @param url 请求地址
     * @param fileParamName 文件参数名
     * @param filePath 文件路径
     * @param params 其他参数
     * @param headers 请求头
     * @param callback 回调接口
     */
    public void uploadFile(String url, String fileParamName, String filePath,
                           Map<String, String> params, Map<String, String> headers,
                           HttpCallback callback) {
        File file = new File(filePath);
        if (!file.exists()) {
            callback.onFailure(new NetworkError(NetworkErrorType.UNKNOWN_ERROR, "File not exists", new IOException("File not exists")));
            return;
        }

        MultipartBody.Builder requestBodyBuilder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);

        // 添加文件
        RequestBody fileBody = RequestBody.create(file,MediaType.parse("application/octet-stream"));
        requestBodyBuilder.addFormDataPart(
                fileParamName,
                file.getName(),
                fileBody
        );

        // 添加其他参数
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                requestBodyBuilder.addFormDataPart(entry.getKey(), entry.getValue());
            }
        }

        RequestBody requestBody = requestBodyBuilder.build();
        post(url, requestBody, headers, callback);
    }

    /**
     * 通用 POST 请求
     */
    private void post(String url, RequestBody requestBody, Map<String, String> headers, HttpCallback callback) {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(requestBody);

        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        Request request = requestBuilder.build();
        executeRequest(request, callback);
    }

    /**
     * 执行请求
     */
    private void executeRequest(Request request, final HttpCallback callback) {
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                NetworkError error = classifyNetworkError(e);
                callback.onFailure(error);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    ResponseBody body = response.body();
                    if (body != null) {
                        callback.onSuccess(body.string());
                    } else {
                        callback.onFailure(new NetworkError(NetworkErrorType.UNKNOWN_ERROR, "Response body is null", null));
                    }
                } else {
                    callback.onFailure(new NetworkError(NetworkErrorType.SERVER_ERROR, "HTTP Error: " + response.code() + " - " + response.message(), null, response.code()));
                }
            }
        });
    }

    /**
     * 构建带参数的URL
     */
    private String buildUrlWithParams(String url, Map<String, String> params) {
        if (params == null || params.isEmpty()) {
            return url;
        }

        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            urlBuilder.addQueryParameter(entry.getKey(), entry.getValue());
        }
        return urlBuilder.build().toString();
    }

    /**
     * 请求回调接口
     */
    public interface HttpCallback {
        void onSuccess(String response);
        void onFailure(NetworkError error);
    }

    /**
     * 网络错误类型
     */
    public enum NetworkErrorType {
        TIMEOUT,           // 请求超时
        NETWORK_UNAVAILABLE, // 网络不可用
        SSL_ERROR,         // SSL错误
        HOST_NOT_FOUND,    // 域名解析失败
        CONNECTION_REFUSED, // 连接被拒绝
        SERVER_ERROR,      // 服务器错误
        UNKNOWN_ERROR      // 未知错误
    }

    /**
     * 网络错误信息类
     */
    public static class NetworkError {
        private NetworkErrorType type;
        private String message;
        private Throwable throwable;
        private int httpCode;

        public NetworkError(NetworkErrorType type, String message, Throwable throwable) {
            this.type = type;
            this.message = message;
            this.throwable = throwable;
        }

        public NetworkError(NetworkErrorType type, String message, Throwable throwable, int httpCode) {
            this.type = type;
            this.message = message;
            this.throwable = throwable;
            this.httpCode = httpCode;
        }

        // getter 方法
        public NetworkErrorType getType() { return type; }
        public String getMessage() { return message; }
        public Throwable getThrowable() { return throwable; }
        public int getHttpCode() { return httpCode; }

        public boolean isTimeout() { return type == NetworkErrorType.TIMEOUT; }
        public boolean isNetworkUnavailable() { return type == NetworkErrorType.NETWORK_UNAVAILABLE; }
        public boolean isServerError() { return type == NetworkErrorType.SERVER_ERROR; }
    }

    /**
     * 分类网络错误
     */
    private NetworkError classifyNetworkError(IOException e) {
        String message = e.getMessage();
        NetworkErrorType type = NetworkErrorType.UNKNOWN_ERROR;

        if (e instanceof SocketTimeoutException) {
            type = NetworkErrorType.TIMEOUT;
        } else if (e instanceof ConnectException) {
            type = NetworkErrorType.CONNECTION_REFUSED;
        } else if (e instanceof SSLException) {
            type = NetworkErrorType.SSL_ERROR;
        } else if (e instanceof UnknownHostException) {
            type = NetworkErrorType.HOST_NOT_FOUND;
        } else if (e instanceof NoRouteToHostException || (message != null && (message.contains("Network is unreachable") || message.contains("ENETUNREACH") || message.contains("ECONNREFUSED")))) {
            type = NetworkErrorType.NETWORK_UNAVAILABLE;
        }
        return new NetworkError(type, e.getMessage(), e);
    }
}
